<?php

Raise::load('core.RaiseObject');
Raise::load('core.RaiseFile');
Raise::load('core.RaiseDateTime');
Raise::load('core.RaiseException');
Raise::load('core.RaisePath');

/**
 * RaiseLog class
 * Provides functionality for logging
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.Core
 * @since 1.2
 */
class RaiseLog extends RaiseObject {
    /**
     * Format of the log message to use when writing to log file
     * @var string
     * @staticvar
     */
    const FORMAT = '$filename$:$line$ [$datetime$] ($type$) $message$';

    /**
     * The log file
     * @var RaiseFile
     */
    protected $file;
    /**
     * The maximum file size
     * @var integer
     */
    protected $maxSize;

    /**
     * Create a new RaiseLog file
     * @param string|RaiseFile $file The file to write to
     * @param integer $file The maximum number of bytes for each file
     */
    public function __construct($file, $maxSize = 2097152) {

        if ($maxSize < 1024) {
            throw new RaiseInvalidArgumentException('Lowest $maxSize should be at least 1024 bytes (1 KB).');
        }

        $this->maxSize = $maxSize;
        if ($file instanceof RaiseFile) {
            $this->file = $file;
        } else {
            $this->file = new RaiseFile($file);
        }
    }

    /**
     * Get the RaiseFile that the log entries are written to
     * @return RaiseFile
     */
    public function file() {
        return $this->file;
    }

    /**
     * Get the maximum file size of each log file
     * @return integer
     */
    public function maxSize() {
        return $this->maxSize;
    }

    /**
     * Write a log entry to the Log file
     * @param string|RaiseException $message If $type is a string, the entry is written as a message. Otherwise if it is a RaiseException, it will parse PHP exceptions/errors into the appropriate format.
     */
    public function write($message) {
        $msg = '';
        if ($message instanceof RaiseException) {
            $a = array(
                '$filename$' => $message->getFile(),
                '$line$' => $message->getLine(),
                '$datetime$' => RaiseDateTime::Now()->toISO8601(),
                '$type$' => $message->getCode(),
                '$message$' => $message->getMessage()
            );
            $msg = str_replace(array_keys($a), $a, self::FORMAT) . "\r\n";
        } else {
            $msg = '[' . RaiseDateTime::Now()->toISO8601() . '] ' . $message;
        }

        $availableSize = $this->maxSize - (strlen($msg) + 1);
        if ($this->file->exists() && $availableSize - $this->file->size() <= 0) {
            $i = 0;
            $filename = RaisePath::pathInfo($this->file->getPathName(), RaisePath::FILENAME);
            $p = strpos($filename, '-');
            if ($p !== false) {
                $filename = substr($filename, 0, $p);
                $i = (int) substr($filename, $p + 1);
            }
            $ext = $this->file->getExtension();
            $file = null;
            do {
                $file = new RaiseFile($filename . '-' . $i . '.' . $ext);
                $i++;
            } while ($file->exists() && $availableSize - $file->size() <= 0);
            $this->file = $file;
        }
        if ($this->file->exists()) {
            $this->file->appendContent($msg);
        } else {
            $this->file->setContent($msg);
        }
        clearstatcache(true, $this->file->getPathName());
    }

}

